﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;

namespace Silverlight.Windows.Controls
{
    public class WindowDeactivatedEventArgs : EventArgs
    {
        private readonly IntPtr _hwnd;

        public WindowDeactivatedEventArgs(IntPtr hwnd)
        {
            _hwnd = hwnd;
        }

        public IntPtr Hwnd { get { return _hwnd; } }
    }

    public class AppWindow
    {
        private HookProc _callback; // Prevent the Garbage Collector from destroying the delegate!
        private IntPtr _hHook = IntPtr.Zero;

        public AppWindow()
        {
            _callback = WindowHook;
        }

        public void Hook()
        {
            Unhook();
            _hHook = SetWindowsHookEx(WH_CALLWNDPROC, _callback, IntPtr.Zero, GetCurrentThreadId());
        }

        public void Unhook()
        {
            if (_hHook != IntPtr.Zero)
                UnhookWindowsHookEx(_hHook);
        }

        public event EventHandler<WindowDeactivatedEventArgs> WindowDeactivated;
        public event EventHandler<EventArgs> AppDeactivated;
 
        [AllowReversePInvokeCalls]
        private IntPtr WindowHook(int code, IntPtr wParam, IntPtr lParam)
        {
            if (code == HC_ACTION)
            {
                var messageInfo = new CWPSTRUCT();
                Marshal.PtrToStructure(lParam, messageInfo);

                if (messageInfo.message == WM_ACTIVATE && (int ) messageInfo.wparam != WA_INACTIVE)
                {
                    var e = WindowDeactivated;
                    if (e != null) e(this, new WindowDeactivatedEventArgs(messageInfo.lparam));
                }
                else if ( messageInfo.message == WM_ACTIVATEAPP && (int ) messageInfo.wparam == FALSE)
                {
                    var e = AppDeactivated;
                    if (e != null) e(this, EventArgs.Empty);
                }
            }
            return CallNextHookEx(_hHook, code, wParam, lParam);
        }

        #region PInvoke
        private const int HC_ACTION = 0;
        private const int WH_CALLWNDPROC = 4;
        private const int WA_INACTIVE = 0;
        private const int WM_ACTIVATE = 0x0006;
        private const int WM_ACTIVATEAPP = 0x001C;
        private const int FALSE = 0;
 

        [StructLayout(LayoutKind.Sequential)]
        public class CWPSTRUCT
        {
            public IntPtr lparam;
            public IntPtr wparam;
            public int message;
            public IntPtr hwnd;
        }

        delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);
        #endregion
    }
}
